<Project>
  <Target Name="CreateAllWrappers" DependsOnTargets="GetListOfTestCmds;FindCmdDirectories">
    <MSBuild
      Projects="$(MSBuildProjectFile)"
      Targets="CreateXunitWrapper;BuildXunitWrapper"
      Properties="_CMDDIR=%(TestDirectories.Identity)"
      Condition="'@(TestDirectories)' != ''" />
  </Target>

  <Target Name="CreateXunitWrapper" DependsOnTargets="CreateXunitFacts">

    <PropertyGroup>
      <_XunitWrapperGen >
        <![CDATA[

$(_XunitProlog)
@(AllXUnitFacts)
$(_XunitEpilog)

]]>
      </_XunitWrapperGen>
      <XunitWrapperGenCsProj>
        <![CDATA[
<Project>

  <Import Project="$(TestProjectDir)Common/dir.sdkbuild.props" />

  <PropertyGroup>
    <OutputPath>$(XUnitTestBinBase)\$(CategoryWithSlash)</OutputPath>
    <RuntimeFrameworkVersion>$(MicrosoftNETCoreAppRuntimewinx64Version)</RuntimeFrameworkVersion>
    <RunAnalyzers>false</RunAnalyzers>
 </PropertyGroup>

  <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props" />

  <ItemGroup>
    <Compile Include="$(XunitWrapper).cs" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="$(TestProjectDir)Common\Coreclr.TestWrapper\Coreclr.TestWrapper.csproj" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="xunit" Version="$(XUnitVersion)" />
    <PackageReference Include="Microsoft.DotNet.XUnitConsoleRunner" Version="$(MicrosoftDotNetXUnitConsoleRunnerVersion)" />
  </ItemGroup>

  <ItemGroup>
    <Content Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
  </ItemGroup>

  <Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" />

</Project>
]]>
      </XunitWrapperGenCsProj>
      <XunitRunnerConfig>
        <![CDATA[
{
    "diagnosticMessages": true,
    "longRunningTestSeconds": 120,
    "shadowCopy": false,
    "preEnumerateTheories": false
}
]]>
      </XunitRunnerConfig>
    </PropertyGroup>

    <!-- <Exec Command="md" -->
    <MakeDir  Directories="$(XunitWrapperGeneratedCSDirBase)$(Category)"/>

    <!-- Write the file -->
    <WriteLinesToFile
      File="$(XunitWrapperSrcDir)\$(XunitWrapper).cs"
      Lines="$(_XunitWrapperGen)"
      Overwrite="true" />

    <!-- Write the file -->
    <WriteLinesToFile
      File="$(XunitWrapperSrcDir)\$(XunitWrapper).csproj"
      Lines="$(XunitWrapperGenCsProj)"
      Overwrite="true" />

    <!-- Write the file -->
    <WriteLinesToFile
      File="$(XunitWrapperSrcDir)\xunit.runner.json"
      Lines="$(XunitRunnerConfig)"
      Overwrite="true" />
  </Target>

  <Target Name="BuildXunitWrapper">
    <MSBuild Projects="$(XunitWrapperSrcDir)\$(XunitWrapper).csproj" Targets="Restore;Build" />
  </Target>

  <Import Project="$(MSBuildThisFileDirectory)Common/testgrouping.proj" />

  <Target Name="CreateXunitFacts" DependsOnTargets="GetListOfTestCmds">
    <!-- NOTE! semicolons must be escaped with %3B boooo -->

    <PropertyGroup>
      <CategoryWithSlash>$([System.IO.Path]::GetRelativePath('$(XunitTestBinBase)', '$(_CMDDIR)'))</CategoryWithSlash>
      <Category Condition="'$(RunningOnUnix)' != 'true'" >$([System.String]::Copy('$(CategoryWithSlash)').Replace('\','.'))</Category>
      <Category Condition="'$(RunningOnUnix)' == 'true'" >$([System.String]::Copy('$(CategoryWithSlash)').Replace('/','.'))</Category>
      <XunitWrapper>$(Category).XUnitWrapper</XunitWrapper>
      <XunitWrapperSrcDir>$(XunitWrapperGeneratedCSDirBase)$(Category)</XunitWrapperSrcDir>
      <MobilePlatform Condition=" '$(TargetOS)' == 'android' ">android</MobilePlatform>
      <MobilePlatform Condition=" '$(TargetOS)' == 'ios' Or '$(TargetOS)' == 'iossimulator' Or '$(TargetOS)' == 'tvos' Or '$(TargetOS)' == 'tvossimulator' ">apple</MobilePlatform>
      <IsMobile>false</IsMobile>
      <IsMobile Condition=" '$(TargetOS)' == 'android' Or '$(TargetOS)' == 'ios' Or '$(TargetOS)' == 'iossimulator' Or '$(TargetOS)' == 'tvos' Or '$(TargetOS)' == 'tvossimulator' ">true</IsMobile>
    </PropertyGroup>

    <PropertyGroup>
      <_XunitProlog Condition=" '$(_XunitProlog)'=='' and '$(IsMobile)'=='false' ">
        <![CDATA[
using Xunit%3B
using Xunit.Abstractions%3B
using System%3B
using System.Collections.Generic%3B
using System.Diagnostics%3B
using System.Reflection%3B
using System.Text.RegularExpressions%3B
using CoreclrTestLib%3B
using System.IO%3B

namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\","").Replace("-","_"))
{
        internal class _Global
        {
            internal static bool runningInWindows%3B
            internal static string reportBase%3B
            internal static string testBinaryBase%3B
            internal static string coreRoot%3B
            internal static string category%3B
            internal static string helixUploadRoot%3B

            static _Global()
            {
                reportBase = Environment.GetEnvironmentVariable(%22XunitTestReportDirBase%22)%3B
                testBinaryBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)%3B
                coreRoot = Environment.GetEnvironmentVariable(%22CORE_ROOT%22)%3B
                category = "$([System.String]::Copy($(Category)).Replace(".","_").Replace("\","").Replace("-","_"))"%3B
                helixUploadRoot = Environment.GetEnvironmentVariable(%22HELIX_WORKITEM_UPLOAD_ROOT%22)%3B
                if (!String.IsNullOrEmpty(helixUploadRoot)) {
                    reportBase = Path.Combine(Path.GetFullPath(helixUploadRoot), "Reports")%3B
                }

                if (String.IsNullOrEmpty(reportBase)) {
                    reportBase = Path.Combine(testBinaryBase, "Reports")%3B
                }
                else
                {
                    reportBase = Path.GetFullPath(reportBase)%3B
                }

                if (String.IsNullOrEmpty(coreRoot)) {
                    throw new ArgumentException("Environment variable CORE_ROOT is not set")%3B
                }

                coreRoot = Path.GetFullPath(coreRoot)%3B

                string operatingSystem = Environment.GetEnvironmentVariable("OS")%3B
                runningInWindows = (operatingSystem != null && operatingSystem.StartsWith("Windows"))%3B
            }
        }
]]>
      </_XunitProlog>
      <_XunitProlog Condition=" '$(_XunitProlog)'=='' and '$(IsMobile)'=='true' ">
        <![CDATA[
using Xunit%3B
using Xunit.Abstractions%3B
using System%3B
using System.Collections.Generic%3B
using System.Diagnostics%3B
using System.Reflection%3B
using System.Text.RegularExpressions%3B
using CoreclrTestLib%3B
using System.IO%3B

namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\","").Replace("-","_"))
{
        public class _Global : IDisposable
        {
            public bool runningInWindows%3B
            public string reportBase%3B
            public string testBinaryBase%3B
            public string coreRoot%3B
            public string category%3B
            public string helixUploadRoot%3B
            public MobileAppHandler handler = new MobileAppHandler()%3B

            public _Global()
            {
                reportBase = Environment.GetEnvironmentVariable(%22XunitTestReportDirBase%22)%3B
                testBinaryBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)%3B
                coreRoot = Environment.GetEnvironmentVariable(%22CORE_ROOT%22)%3B
                category = "$([System.String]::Copy($(Category)).Replace(".","_").Replace("\","").Replace("-","_"))"%3B
                helixUploadRoot = Environment.GetEnvironmentVariable(%22HELIX_WORKITEM_UPLOAD_ROOT%22)%3B
                int retCode = -100%3B

                if (!String.IsNullOrEmpty(helixUploadRoot)) {
                    reportBase = Path.Combine(Path.GetFullPath(helixUploadRoot), "Reports")%3B
                }

                if (String.IsNullOrEmpty(reportBase)) {
                    reportBase = Path.Combine(testBinaryBase, %22Reports%22)%3B
                }
                else
                {
                    reportBase = Path.GetFullPath(reportBase)%3B
                }

                if (String.IsNullOrEmpty(coreRoot)) {
                    throw new ArgumentException("Environment variable CORE_ROOT is not set")%3B
                }

                coreRoot = Path.GetFullPath(coreRoot)%3B

                string operatingSystem = Environment.GetEnvironmentVariable("OS")%3B
                runningInWindows = (operatingSystem != null && operatingSystem.StartsWith("Windows"))%3B

                retCode = handler.InstallMobileApp(%22$(MobilePlatform)%22, category, testBinaryBase, reportBase, %22$(TargetOS)%22.ToLowerInvariant())%3B
                Assert.True(retCode == 0, "Failed to install mobile app.")%3B
            }

            public void Dispose()
            {
                int retCode = -100%3B
                retCode = handler.UninstallMobileApp(%22$(MobilePlatform)%22, category, testBinaryBase, reportBase, %22$(TargetOS)%22.ToLowerInvariant())%3B
                Assert.True(retCode == 0, "Failed to uninstall mobile app.")%3B
            }
        }

        [CollectionDefinition("Runtime test collection")]
        public class RuntimeTestCollection : ICollectionFixture<_Global>
        {
            // This class has no code, and is never created. Its purpose is simply
            // to be the place to apply [CollectionDefinition] and all the
            // ICollectionFixture<> interfaces.
        }
]]>
      </_XunitProlog>
      <_XunitEpilog Condition=" '$(_XunitEpilog)'=='' ">
      <![CDATA[
}

]]>
      </_XunitEpilog>
    </PropertyGroup>

    <PropertyGroup>
      <TestExecutableReplacement Condition="'$(TestWrapperTargetsWindows)' != 'true' ">testExecutable = testExecutable.Replace("\\", "/")%3B</TestExecutableReplacement>
    </PropertyGroup>

    <ItemGroup>
      <AllCMDsPresent Include="$(_CMDDIR)\**\*.$(TestScriptExtension)" Exclude="$(_CMDDIR)\**\AppBundle\*.$(TestScriptExtension)" />
      <AllCMDsPresent Remove="$(_CMDDIR)\**\run-v8.sh" Condition="'$(TargetArchitecture)' == 'wasm'" />
      <AllCMDsPresent Remove="@(MergedRunnableTestPaths)" />
      <AllCMDsPresent Remove="@(OutOfProcessTestPaths)" />
    </ItemGroup>

    <ItemGroup Condition="'@(AllCMDsPresent)' != ''">
      <TestGroupingDistinctWithCase Include="@(TestGrouping->Metadata('FullPath')->DistinctWithCase())" />
      <TestGroupingNotRelevant Include="@(TestGroupingDistinctWithCase)" Exclude="@(AllCMDsPresent)" />
      <GroupedCMDs Include="@(TestGroupingDistinctWithCase)" Exclude="@(TestGroupingNotRelevant)" />
      <GroupedCMDs Include="@(AllCMDsPresent)" Exclude="@(GroupedCMDs)">
        <TestGroup>$(Category)</TestGroup>
      </GroupedCMDs>
      <AllCMDExcludeFilter Include="@(ExcludeList->Metadata('FullPath'))" Condition="$(HaveExcludes)" />
      <AllCMDs Include="@(GroupedCMDs)" Exclude="@(AllCMDExcludeFilter)">
        <RelativeToCMDDIR>$([MSBuild]::MakeRelative($(_CMDDIR), %(FullPath)))</RelativeToCMDDIR>
      </AllCMDs>
      <AllCommands Include="@(AllCMDs)" Condition="@(AllCMDs->Count()) &gt; 0">
        <DisplayName>$([MSBuild]::MakeRelative($(XunitTestBinBase), %(AllCMDs.FullPath)))</DisplayName>
        <FactName Condition="'$(RunningOnUnix)' != 'true'" >_$([MSBuild]::ValueOrDefault(%(AllCMDs.RelativeToCMDDIR),"").Replace(".","_").Replace("\","_").Replace("-","_"))</FactName>
        <ClassName Condition="'$(RunningOnUnix)' != 'true'" >_$([MSBuild]::ValueOrDefault(%(AllCMDs.RelativeToCMDDIR),"").Replace($(TestScriptExtension),"").Replace(".","_").Replace("\","_").Replace("-","_"))</ClassName>
        <FactName Condition="'$(RunningOnUnix)' == 'true'" >_$([MSBuild]::ValueOrDefault(%(AllCMDs.RelativeToCMDDIR),"").Replace(".","_").Replace("/","_").Replace("-","_"))</FactName>
        <ClassName Condition="'$(RunningOnUnix)' == 'true'" >_$([MSBuild]::ValueOrDefault(%(AllCMDs.RelativeToCMDDIR), '').Replace($(TestScriptExtension),'').Replace('.','_').Replace('/','_').Replace('-','_'))</ClassName>
        <TestGroup>%(AllCMDs.TestGroup)</TestGroup>
        <XUnitFact Condition=" '$(IsMobile)'=='false' ">
          <![CDATA[

        public class %(AllCommands.ClassName)
        {
            private readonly ITestOutputHelper output%3B

            public %(AllCommands.ClassName)(ITestOutputHelper output)
            {
                this.output = output%3B
            }

            [Fact(DisplayName=@"%(AllCommands.DisplayName)")]
            [Trait("TestGroup", "%(AllCommands.TestGroup)")]
            public void %(AllCommands.FactName)()
            {
                int ret = -100%3B
                string outputFile = null%3B
                string errorFile = null%3B
                string testExecutable = null%3B
                string outputDir = null%3B
                Exception infraEx = null%3B

                try
                {
                  CoreclrTestWrapperLib wrapper = new CoreclrTestWrapperLib()%3B
                  string testSubfolder = @"\$(Category)\$([System.String]::Copy('%(AllCMDs.RelativeDir)').Replace("$(_CMDDIR)$([System.IO.Path]::DirectorySeparatorChar)",''))"%3B
                  outputFile = System.IO.Path.GetFullPath(_Global.reportBase + testSubfolder + @"%(AllCMDs.FileName).output.txt")%3B
                  errorFile = System.IO.Path.GetFullPath(_Global.reportBase + testSubfolder + @"%(AllCMDs.FileName).error.txt")%3B
                  testExecutable = System.IO.Path.GetFullPath(_Global.testBinaryBase + @"$([System.String]::Copy('%(AllCMDs.FullPath)').Replace("$(_CMDDIR)",''))")%3B
                  $(TestExecutableReplacement)
                  outputDir = System.IO.Path.GetDirectoryName(outputFile)%3B

                  if (!_Global.runningInWindows) {
                      testExecutable = testExecutable.Replace(".cmd", ".sh")%3B
                  }

                  System.IO.Directory.CreateDirectory(_Global.reportBase + testSubfolder)%3B

                  ret = wrapper.RunTest(testExecutable, outputFile, errorFile, _Global.category, _Global.testBinaryBase, outputDir)%3B
                }
                catch (Exception ex)
                {
                    infraEx = ex%3B
                }

                if (infraEx != null)
                {
                    Assert.Fail("Test Infrastructure Failure: " + infraEx.ToString())%3B
                }
                else
                {
                    List<string> testOutput = new List<string>()%3B

                    try
                    {
                        testOutput.AddRange(System.IO.File.ReadAllLines(errorFile))%3B
                    }
                    catch (Exception ex)
                    {
                        testOutput.Add("Unable to read error file: " + errorFile)%3B
                        testOutput.Add(ex.ToString())%3B
                    }

                    testOutput.Add(string.Empty)%3B
                    testOutput.Add("Return code:      " + ret)%3B
                    testOutput.Add("Raw output file:      " + outputFile)%3B
                    testOutput.Add("Raw output:")%3B

                    try
                    {
                        testOutput.AddRange(System.IO.File.ReadAllLines(outputFile))%3B
                    }
                    catch(Exception ex)
                    {
                        testOutput.Add("Unable to read output file: " + outputFile)%3B
                        testOutput.Add(ex.ToString())%3B
                    }

                    testOutput.Add("To run the test:")%3B
                    testOutput.Add("> set CORE_ROOT=" + _Global.coreRoot)%3B
                    testOutput.Add("> " + testExecutable)%3B

                    var unicodeControlCharsRegex = new Regex("%5C%5Cp{C}+")%3B

                    // Remove all characters that have no visual or spatial representation.
                    for (int i = 0%3B i < testOutput.Count%3B i++)
                    {
                        string line = testOutput[i]%3B
                        line = unicodeControlCharsRegex.Replace(line, string.Empty)%3B
                        testOutput[i] = line%3B
                    }

                    foreach (string line in testOutput)
                    {
                        output.WriteLine(line)%3B
                    }

                    Assert.True(ret == CoreclrTestWrapperLib.EXIT_SUCCESS_CODE, string.Join(Environment.NewLine, testOutput))%3B
                }
            }
        }

        ]]>
        </XUnitFact>
        <XUnitFact Condition=" '$(IsMobile)'=='true' ">
          <![CDATA[
        [Collection("Runtime test collection")]
        public class %(AllCommands.ClassName)
        {
            private readonly ITestOutputHelper output%3B
            _Global globalVar%3B

            public %(AllCommands.ClassName)(ITestOutputHelper output, _Global globalVar)
            {
                this.output = output%3B
                this.globalVar = globalVar%3B
            }

            [Fact(DisplayName=@"%(AllCommands.DisplayName)")]
            [Trait("TestGroup", "%(AllCommands.TestGroup)")]
            public void %(AllCommands.FactName)()
            {
                int ret = -100%3B
                string outputFile = null%3B
                string errorFile = null%3B
                string testExecutable = null%3B
                string outputDir = null%3B
                Exception infraEx = null%3B

                try
                {
                  CoreclrTestWrapperLib wrapper = new CoreclrTestWrapperLib()%3B
                  string testSubfolder = @"\$(Category)\$([System.String]::Copy('%(AllCMDs.RelativeDir)').Replace("$(_CMDDIR)$([System.IO.Path]::DirectorySeparatorChar)",''))"%3B
                  outputFile = System.IO.Path.GetFullPath(globalVar.reportBase + testSubfolder + @"%(AllCMDs.FileName).output.txt")%3B
                  errorFile = System.IO.Path.GetFullPath(globalVar.reportBase + testSubfolder + @"%(AllCMDs.FileName).error.txt")%3B
                  testExecutable = System.IO.Path.GetFullPath(globalVar.testBinaryBase + @"$([System.String]::Copy('%(AllCMDs.FullPath)').Replace("$(_CMDDIR)",''))")%3B
                  $(TestExecutableReplacement)
                  outputDir = System.IO.Path.GetDirectoryName(outputFile)%3B

                  if (!globalVar.runningInWindows) {
                      testExecutable = testExecutable.Replace(".cmd", ".sh")%3B
                  }

                  System.IO.Directory.CreateDirectory(globalVar.reportBase + testSubfolder)%3B

                  ret = wrapper.RunTest(testExecutable, outputFile, errorFile, globalVar.category, globalVar.testBinaryBase, outputDir)%3B
                }
                catch (Exception ex)
                {
                    infraEx = ex%3B
                }

                if (infraEx != null)
                {
                    Assert.Fail("Test Infrastructure Failure: " + infraEx.ToString())%3B
                }
                else
                {
                    List<string> testOutput = new List<string>()%3B

                    try
                    {
                        testOutput.AddRange(System.IO.File.ReadAllLines(errorFile))%3B
                    }
                    catch (Exception ex)
                    {
                        testOutput.Add("Unable to read error file: " + errorFile)%3B
                        testOutput.Add(ex.ToString())%3B
                    }

                    testOutput.Add(string.Empty)%3B
                    testOutput.Add("Return code:      " + ret)%3B
                    testOutput.Add("Raw output file:      " + outputFile)%3B
                    testOutput.Add("Raw output:")%3B

                    try
                    {
                        testOutput.AddRange(System.IO.File.ReadAllLines(outputFile))%3B
                    }
                    catch(Exception ex)
                    {
                        testOutput.Add("Unable to read output file: " + outputFile)%3B
                        testOutput.Add(ex.ToString())%3B
                    }

                    testOutput.Add("To run the test:")%3B
                    testOutput.Add("> set CORE_ROOT=" + globalVar.coreRoot)%3B
                    testOutput.Add("> " + testExecutable)%3B

                    var unicodeControlCharsRegex = new Regex("%5C%5Cp{C}+")%3B

                    // Remove all characters that have no visual or spatial representation.
                    for (int i = 0%3B i < testOutput.Count%3B i++)
                    {
                        string line = testOutput[i]%3B
                        line = unicodeControlCharsRegex.Replace(line, string.Empty)%3B
                        testOutput[i] = line%3B
                    }

                    foreach (string line in testOutput)
                    {
                        output.WriteLine(line)%3B
                    }

                    // Add Android app running log to testOutput
                    if (ret != CoreclrTestWrapperLib.EXIT_SUCCESS_CODE)
                    {
                        string androidLogFile = System.IO.Path.Combine(outputDir, "adb-logcat-net.dot." + globalVar.category + "-net.dot.MonoRunner.log")%3B
                        if(File.Exists(androidLogFile))
                        {
                            testOutput.AddRange(System.IO.File.ReadAllLines(androidLogFile))%3B
                        }
                    }

                    Assert.True(ret == CoreclrTestWrapperLib.EXIT_SUCCESS_CODE, string.Join(Environment.NewLine, testOutput))%3B
                }
            }
        }
        ]]>
        </XUnitFact>
      </AllCommands>
      <AllXUnitFacts Include= "@(AllCommands->Metadata(XUnitFact))" />
    </ItemGroup>
  </Target>
</Project>
